use std::sync::Arc;
use crate::consumer::{ConsumeLogs, ConsumeMetrics, ConsumeTraces};
use crate::pipeline::{LogsProcessor, MetricsProcessor, TracesProcessor};

/// Builder for constructing traces processing pipelines.
pub struct TracesPipelineBuilder {
    pub(crate) sink: Arc<dyn ConsumeTraces + Send + Sync + 'static>,
    pub(crate) processors: Vec<Box<dyn TracesProcessor>>, // in top-to-bottom order
}

impl TracesPipelineBuilder {
    /// Create a new traces pipeline builder with the given sink.
    pub fn new(sink: Arc<dyn ConsumeTraces + Send + Sync + 'static>) -> Self {
        Self {
            sink,
            processors: Vec::new(),
        }
    }

    /// Append a processor to the pipeline.
    pub fn append_processor(mut self, processor: impl TracesProcessor + 'static) -> Self {
        self.processors.push(Box::new(processor));
        self
    }

    /// Builds and returns a trace processing pipeline by chaining all added processors
    /// around the final sink.
    ///
    /// 1. Reverses the list of processors (using `.rev()`),
    /// 2. Starts with `self.sink` as the base consumer,
    /// 3. Folds from right to left, wrapping each processor around the accumulated chain.
    ///
    /// This results in a nested middleware structure: `p1(p2(p3(...(sink))))`,
    /// where each processor can preprocess traces before delegating to the next.
    ///
    /// # Returns
    ///
    /// An `Arc<dyn ConsumeTraces + Send + Sync + 'static>` that can be safely
    /// shared across threads and used to consume traces through the full pipeline.
    ///
    /// # Note
    ///
    /// This method consumes `self`, taking ownership of both `processors` and `sink`.
    /// After calling `build()`, the builder is no longer usable.
    pub fn build(self) -> Arc<dyn ConsumeTraces + Send + Sync + 'static> {
        self.processors
            .into_iter()
            .rev()
            .fold(self.sink, |next, processor| processor.wrap(next))
    }
}

/// Builder for constructing metrics processing pipelines.
pub struct MetricsPipelineBuilder {
    pub(crate) sink: Arc<dyn ConsumeMetrics + Send + Sync + 'static>,
    pub(crate) processors: Vec<Box<dyn MetricsProcessor>>, // in top-to-bottom order
}

impl MetricsPipelineBuilder {
    /// Create a new metrics pipeline builder with the given sink.
    pub fn new(sink: Arc<dyn ConsumeMetrics + Send + Sync + 'static>) -> Self {
        Self {
            sink,
            processors: Vec::new(),
        }
    }

    /// Append a processor to the pipeline.
    pub fn append_processor(mut self, processor: impl MetricsProcessor + 'static) -> Self {
        self.processors.push(Box::new(processor));
        self
    }

    /// Build the metrics processing pipeline.
    pub fn build(self) -> Arc<dyn ConsumeMetrics + Send + Sync + 'static> {
        self.processors
            .into_iter()
            .rev()
            .fold(self.sink, |next, processor| processor.wrap(next))
    }
}

/// Builder for constructing logs processing pipelines.
pub struct LogsPipelineBuilder {
    pub(crate) sink: Arc<dyn ConsumeLogs + Send + Sync + 'static>,
    pub(crate) processors: Vec<Box<dyn LogsProcessor>>, // in top-to-bottom order
}

impl LogsPipelineBuilder {
    /// Create a new logs pipeline builder with the given sink.
    pub fn new(sink: Arc<dyn ConsumeLogs + Send + Sync + 'static>) -> Self {
        Self {
            sink,
            processors: Vec::new(),
        }
    }

    /// Append a processor to the pipeline.
    pub fn append_processor(mut self, processor: impl LogsProcessor + 'static) -> Self {
        self.processors.push(Box::new(processor));
        self
    }

    /// Build the logs processing pipeline.
    pub fn build(self) -> Arc<dyn ConsumeLogs + Send + Sync + 'static> {
        self.processors
            .into_iter()
            .rev()
            .fold(self.sink, |next, processor| processor.wrap(next))
    }
}